package com.turtle.learning.auth.utils;

import com.turtle.learning.auth.constant.SecurityConstants;
import com.turtle.learning.auth.dto.LoginUserInfo;
import com.turtle.learning.users.entity.User;
import com.turtle.learning.users.service.impl.UserServiceImpl;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * Token 操作类
 *
 * @author turtle
 * @since: 2020-05-05
 */
@Component
@Slf4j
public class TokenOperator {

    protected static final long MILLIS_SECOND = 1000;
    protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;
    @Autowired
    private UserServiceImpl userService;

    /**
     * 请求头
     */
    @Value("${token.header}")
    private String header;
    /**
     * 密钥
     */
    @Value("${token.secret}")
    private String secret;
    /**
     * 过期时间
     */
    @Value("${token.expireTime}")
    private Integer expireTime;

    /**
     * 生成token
     *
     * @param loginUserInfo 登录用户信息
     * @return token 凭证
     */
    public String generateToken(LoginUserInfo loginUserInfo) {
        String uuid = UUID.randomUUID().toString();
        Long tokenExpireTime = System.currentTimeMillis() + expireTime * MILLIS_MINUTE;

        Map<String, Object> claims = new HashMap<>(3);
        claims.put(SecurityConstants.LOGIN_USER_ID, loginUserInfo.getUserId());
        claims.put(SecurityConstants.LOGIN_UUID, uuid);
        claims.put(SecurityConstants.TOKEN_EXPIRE_TIME, tokenExpireTime);
        return Jwts.builder()
            .setClaims(claims)
            .signWith(SignatureAlgorithm.HS512, secret).compact();

    }

    /**
     * 通过token获取用户信息
     *
     * @param request 请求体
     * @return LoginUserInfo 用户信息
     */
    public LoginUserInfo getUserInfo(HttpServletRequest request) {
        // 获取请求头中的token
        String token = this.getToken(request);
        if (token != null) {
            // 解析token，获取用户信息
            Claims claims = this.parseToken(token);
            Integer uid = (Integer) claims.get(SecurityConstants.LOGIN_USER_ID);
            String uuid = (String) claims.get(SecurityConstants.LOGIN_UUID);
            Long tokenExpireTime = (Long) claims.get(SecurityConstants.TOKEN_EXPIRE_TIME);
            User user = userService.getById(uid);
            return LoginUserInfo.builder()
                .userId(uid)
                .uuid(uuid)
                .expireTime(tokenExpireTime)
                .user(user)
                .build();
        }
        return null;
    }

    /**
     * 解析token
     *
     * @param token 凭证
     * @return Claims 数据
     */

    public Claims parseToken(String token) {

        return Jwts.parser()
            .setSigningKey(secret)
            .parseClaimsJws(token)
            .getBody();
    }

    /**
     * 获取请求header里的token值
     *
     * @param request 请求体
     * @return token 凭证
     */
    public String getToken(HttpServletRequest request) {

        String token = request.getHeader(header);
        if (StringUtils.isNotEmpty(token) && token.startsWith(SecurityConstants.TOKEN_PREFIX)) {
            return token.replace(SecurityConstants.TOKEN_PREFIX, "");
        } else {
            return null;
        }

    }
}
